class_name Hero
extends CharacterBody2D

# 角色状态枚举
enum State {
	IDLE,			# 空闲状态
	RUNNING,		# 跑步状态
	JUMP,			# 跳跃状态
	FALL,			# 下落状态
	LANDING,		# 落地下蹲
	WALL_SLIDING,	# 滑墙
	WALL_JUMP,		# 蹬墙跳
	ATTACK_1,		#一段攻击
	ATTACK_2,		#二段攻击
	ATTACK_3,		#三段攻击
	HURT,			#承受伤害
	DYING,			#死亡
	SLIDING_START,		#滑铲开始
	SLIDING_LOOP,	#滑铲
	SLIDING_END,	#滑铲结束
}

# 定义地面状态（可以认为是稳定状态）
const GROUND_STATES := [
	State.IDLE, State.RUNNING, State.LANDING,
	State.ATTACK_1, State.ATTACK_2, State.ATTACK_3
]
const RUN_SPEED := 200.00  # 跑步速度
const FLOOR_ACCELERATION := RUN_SPEED / 0.2  # 地面加速度（基于时间计算）
const AIR_ACCELERATION := RUN_SPEED / 0.4   # 空中加速度（比地面加速度小）
const JUMP_VELOCITY := -300.00  # 跳跃速度（负值表示向上）
const WALL_JUMP_VELOCITY := Vector2(300,-280)# 墙跳速度向量 (水平速度, 垂直速度)
const KO_MAOUNT := 300.00
const SLIDING_DURATION := 0.5
const SLIDING_SPEED := 480.00
const SLIDING_ENERGY := 4
const LANDING_HEIGHT := 100

@export var can_combo :=false

# 从项目设置中获取重力值
var default_gravity := ProjectSettings.get("physics/2d/default_gravity") as float
var is_first_tick := false # 是否是状态开始的第一帧
var is_combo_requested := false
var pending_damage:Damage
var fall_from_y:float
var interacting_wich:Array[Interactable]

# 获取子节点引用
@onready var graphics: Node2D = $graphics # 图形节点，用于翻转角色朝向
#@onready var sprite_2d: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer # 动画播放器
@onready var coyote_timer: Timer = $coyoteTimer # 土狼时间计时器，用于实现离地后短暂时间内仍可跳跃
@onready var jump_request_timer: Timer = $jumpRequestTimer  # 跳跃请求计时器，用于处理跳跃输入缓冲
@onready var check_hand: RayCast2D = $graphics/checkHand  # 手部检测射线，用于检测墙面
@onready var check_foot: RayCast2D = $graphics/checkFoot # 脚部检测射线，用于检测墙面
@onready var state_machine: StateMachine = $StateMachine # 状态机
@onready var stats: Stats = $Stats
@onready var slide_request_timer: Timer = $slideRequestTimer
@onready var interacting_icon: AnimatedSprite2D = $interactingIcon




# 处理未处理的输入事件
func _unhandled_input(event: InputEvent) -> void:
	# 当按下跳跃键时，启动跳跃请求计时器
	if event.is_action_pressed("jump"):
		jump_request_timer.start()
		
	# 当释放跳跃键时，停止跳跃请求计时器
	# 如果当前跳跃上升阶段，则通过将y速度减半来实现短按跳跃低，长按跳跃高
	if event.is_action_released("jump"):
		jump_request_timer.stop()
		if velocity.y < JUMP_VELOCITY / 2:
			velocity.y = JUMP_VELOCITY / 2
	if event.is_action_pressed("attack") and can_combo:
		is_combo_requested = true
		
	if event.is_action_pressed("slide"):
		slide_request_timer.start()
	
	if event.is_action_pressed("interact") and interacting_wich:
		interacting_wich.back().interact()

		
		

# 根据当前状态处理物理逻辑
func tick_physics(state: State, delta: float) -> void:
	interacting_icon.visible = not interacting_wich.is_empty()
	
	match state:
		State.IDLE:
			move(default_gravity, delta)  # 空闲状态下也可以移动（例如从平台上滑落）
			
		State.RUNNING:
			move(default_gravity, delta)  # 跑步状态处理移动
			
		State.JUMP:
			move(0.0 if is_first_tick else default_gravity, delta)  # 跳跃状态处理移动和重力
			
		State.FALL:
			move(default_gravity, delta)  # 下落状态处理移动和重力
			
		State.LANDING:
			stand(default_gravity,delta)  
		
		State.WALL_SLIDING:
			move(default_gravity / 10, delta)  # 滑墙状态处理移动和重力
			graphics.scale.x =get_wall_normal().x
		
		State.WALL_JUMP:
			if state_machine.state_time < 0.05:
				stand(0.0 if is_first_tick else default_gravity,delta)
				graphics.scale.x =get_wall_normal().x
			else:
				move(default_gravity, delta) 
				
		State.ATTACK_1,State.ATTACK_2,State.ATTACK_3:
			stand(default_gravity, delta) 
			
		State.HURT,State.DYING:
			stand(default_gravity, delta) 
			
			
		State.SLIDING_END:
			stand(default_gravity, delta) 
			
		State.SLIDING_START,State.SLIDING_LOOP:
			slide(delta) 
		
	is_first_tick = false



# 移动函数，处理角色的移动和重力
func move(gravity: float, delta: float) -> void:
	var direction := Input.get_axis("move_left", "move_right")	# 获取输入方向（-1左，0无输入，1右）
	var acceleration := FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION# 根据是否在地面上选择加速度
	velocity.x = move_toward(velocity.x, direction * RUN_SPEED, acceleration * delta)# 应用加速度到水平速度
	velocity.y += gravity * delta		# 应用重力
	
	if not is_zero_approx(direction):# 如果方向非零，则翻转精灵图
		graphics.scale.x = -1 if direction < 0 else +1
	move_and_slide()# 应用移动
	
# 站立函数，水平速度减为0
func stand(gravity:float , delta:float) -> void:
	var acceleration := FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION
	velocity.x = move_toward(velocity.x, 0.0, acceleration * delta)# 应用加速度到水平速度
	velocity.y += gravity * delta# 应用重力
	move_and_slide()# 应用移动
	
func slide(delta: float) -> void:
	velocity.x = graphics.scale.x * SLIDING_SPEED
	velocity.y += default_gravity * delta# 应用重力
	move_and_slide()# 应用移动

func register_interactable(value:Interactable)->void:
	if state_machine.current_state == State.DYING:
		return
	if value in interacting_wich:
		return
	interacting_wich.append(value)

func unregister_interactable(value:Interactable)->void:
	interacting_wich.erase(value)
	

	
# 检查是否可以滑墙
func can_wall_slide()->bool:
	return is_on_wall() and check_hand.is_colliding() and check_foot.is_colliding()

#检查是否可以滑铲
func should_slide() ->  bool:
	if slide_request_timer.is_stopped():
		return false
	if stats.energy < SLIDING_ENERGY:
		return false
	return not check_foot.is_colliding()

# 根据当前状态和条件获取下一个状态
func get_next_state(state: State) -> int:
	if stats.health == 0:
		return state_machine.KEEP_CURRENT if state == State.DYING else State.DYING
	if pending_damage:
		return State.HURT
	
	var can_jump := is_on_floor() or coyote_timer.time_left > 0			# 检查是否能够跳跃（在地面上或土狼时间内）
	var should_jump := can_jump and jump_request_timer.time_left > 0	# 检查是否应该跳跃（能够跳跃且跳跃请求计时器还在运行）
	if should_jump:
		return State.JUMP
	
	if state in GROUND_STATES and not is_on_floor():	# 如果不在地面上，转换为下落状态
		return State.FALL
		
	var direction := Input.get_axis("move_left", "move_right")			# 获取输入方向和是否静止（无输入且水平速度接近零）
	var is_still := is_zero_approx(direction) and is_zero_approx(velocity.x)
	
	# 根据当前状态进行状态转换
	match state:
		State.IDLE:
			if Input.is_action_just_pressed("attack"):
				return State.ATTACK_1
			if should_slide():
				return State.SLIDING_START
			if not is_still:		# 如果不静止，转换为跑步状态
				return State.RUNNING
				
		State.RUNNING:
			if Input.is_action_just_pressed("attack"):
				return State.ATTACK_1
			if should_slide():
				return State.SLIDING_START
			if is_still:			# 如果静止，转换为空闲状态
				return State.IDLE
				
		State.JUMP:
			if velocity.y >= 0:		# 如果y速度大于等于0（开始下落），转换为下落状态
				return State.FALL
				
		State.FALL:
			if is_on_floor():		# 如果落地，根据是否静止转换为空闲或跑步状态
				var height := global_position.y - fall_from_y
				return State.LANDING if height >=LANDING_HEIGHT else State.RUNNING
			if  can_wall_slide():	# 检查是否可以滑墙
				return State.WALL_SLIDING
				
		State.LANDING:
			if not animation_player.is_playing():	# 落地动画播放完毕
				return State.IDLE
		
		State.WALL_SLIDING:
			if jump_request_timer.time_left>0:		# 有跳跃输入
				return State.WALL_JUMP
			if is_on_floor():		# 落地
				return State.IDLE
			if not is_on_wall():	# 离开墙面
				return State.FALL
				
		State.WALL_JUMP:
			if  can_wall_slide() and not is_first_tick:
				return State.WALL_SLIDING
			#逻辑同正常跳跃
			if velocity.y >= 0:		# 开始下落
				return State.FALL
				
		State.ATTACK_1:
			if not animation_player.is_playing():
				return State.ATTACK_2 if is_combo_requested else State.IDLE
				
		State.ATTACK_2:
			if not animation_player.is_playing():
				return State.ATTACK_3 if is_combo_requested else State.IDLE
				
		State.ATTACK_3:
			if not animation_player.is_playing():
				return State.IDLE
				
		State.HURT:
			if not animation_player.is_playing():
				return State.IDLE
				
		State.SLIDING_START:
			if not animation_player.is_playing():
				return State.SLIDING_LOOP
				
		State.SLIDING_END:
			if not animation_player.is_playing():
				return State.IDLE
	
		State.SLIDING_LOOP:
			if state_machine.state_time > SLIDING_DURATION or is_on_wall():
				return State.SLIDING_END
	
	
	return state_machine.KEEP_CURRENT	# 如果没有状态转换，保持当前状态

# 状态转换时的处理
func transition_state(from: State, to: State) -> void:
	#print("[%s] %s → %s" %[
		#Engine.get_physics_frames(),
		#State.keys()[from] if from != -1 else "开始！",
		#State.keys()[to],
	#])
	# 如果从非地面状态转换到地面状态，停止土狼计时器
	if from not in GROUND_STATES and to in GROUND_STATES:
		coyote_timer.stop()
	
	# 根据目标状态执行相应的操作
	match to:
		State.IDLE:
			animation_player.play("idle")		# 播放空闲动画
		State.RUNNING:
			animation_player.play("running")	# 播放跑步动画
		State.JUMP:
			animation_player.play("jump")		# 播放跳跃动画
			velocity.y = JUMP_VELOCITY			# 设置跳跃速度
			coyote_timer.stop()				 	# 停止土狼计时器
			jump_request_timer.stop()			# 停止跳跃请求计时器
		State.FALL:
			animation_player.play("fall")		# 播放下落动画
			if from in GROUND_STATES and coyote_timer.is_stopped():# 如果是从地面状态转换而来，启动土狼计时器
				coyote_timer.start()
			fall_from_y = global_position.y
				
		State.LANDING:
			animation_player.play("landing")	# 播放落地动画
		
		State.WALL_SLIDING:
			animation_player.play("wall_sliding")	# 播放滑墙动画
			
		State.WALL_JUMP:
			animation_player.play("jump")		# 播放跳跃动画
			velocity = WALL_JUMP_VELOCITY		# 设置墙跳速度
			velocity.x *= get_wall_normal().x 	# 根据墙面法线调整水平速度方向
			jump_request_timer.stop()
			
		State.ATTACK_1:
			animation_player.play("attack_1")
			is_combo_requested = false
			
		State.ATTACK_2:
			animation_player.play("attack_2")
			is_combo_requested = false
			
		State.ATTACK_3:
			animation_player.play("attack_3")
			is_combo_requested = false

		State.HURT:
			animation_player.play("hurt")
			stats.health -= pending_damage.amount
			var dir := pending_damage.source.global_position.direction_to(global_position)
			velocity = dir *  KO_MAOUNT
			pending_damage = null
			
		State.DYING:
			animation_player.play("die")
			interacting_wich.clear()
			
			
		State.SLIDING_START:
			animation_player.play("sliding_start")
			slide_request_timer.stop()
			stats.energy -= SLIDING_ENERGY
			
		State.SLIDING_LOOP:
			animation_player.play("sliding_loop")
			
		State.SLIDING_END:
			animation_player.play("sliding_end")
			
	#if to == State.WALL_JUMP:
		#Engine.time_scale = 0.5
	#if from == State.WALL_JUMP:
		#Engine.time_scale = 1.0
	is_first_tick = true

#func _on_hit_box_hit(hurtbox: Variant) -> void:
	#pass # Replace with function body.

func _on_hurt_box_hurt(hitbox: HitBox) -> void:
	pending_damage = Damage.new()
	pending_damage.amount = 1
	pending_damage.source = hitbox.owner
	
